//
//  YYCycleView.swift
//  CodeLibrary_Swift
//
//  Created by 陆文宇 on 2017/2/4.
//  Copyright © 2017年 陆文宇. All rights reserved.
//

import UIKit
import Kingfisher

@objc protocol YYCycleViewDelegate: NSObjectProtocol {
    
    /**
     *  已经选取图片
     *
     *  - Parameters:
     *      - cycleView: 轮播视图对象
     *      - index:     图片位置坐标
     */
    @objc optional func cycleView(_ cycleView: YYCycleView, didSelectImageAt index: Int) -> Void
    /**
     *  将要开始拖拽
     *
     *  - Parameters:
     *      - cycleView: 轮播视图对象
     *      - index:     拖拽前图片位置坐标
     */
    @objc optional func cycleView(_ cycleView: YYCycleView, willBeginDraggingAt index: Int) -> Void
    /**
     *  已经结束拖动
     *
     *  - Parameters:
     *      - cycleView: 轮播视图对象
     *      - index:     静止后图片位置坐标
     */
    @objc optional func cycleView(_ cycleView: YYCycleView, didEndDeceleratingAt index: Int) -> Void
    
}


class YYCycleView: UIView, UIScrollViewDelegate {
    
    weak var yyDelegate: YYCycleViewDelegate?
    
    /// 图片数组
    var images: Array<Any>
    /// 当前图片位置坐标
    var currentIndex: Int {
        set {
            guard newValue >= 0 && newValue < images.count else {
                return
            }
            
            if canCycle {
                scrollView.contentOffset = CGPoint(x: frame.size.width * CGFloat(newValue + 1), y: 0)
            } else {
                scrollView.contentOffset = CGPoint(x: frame.size.width * CGFloat(newValue), y: 0)
            }
            pageControl.currentPage = newValue
        }
        
        get {
            let index: Int = Int(scrollView.contentOffset.x / frame.size.width)
            if canCycle {
                return index - 1
            } else {
                return index
            }
        }
    }
    /// 是否可以轮播
    let canCycle: Bool
    /// 是否自动跳转(只读属性)
    private(set) var isRunning: Bool = false
    /// 是否展示页面控制器. default is true
    var isShowPageControl: Bool {
        set {
            pageControl.isHidden = !newValue
        }
        
        get {
            return !pageControl.isHidden
        }
    }
    /// 页面控制器
    var pageControl: UIPageControl!
    private(set) var animationDuration: TimeInterval!
    private var scrollView: UIScrollView!
    private var timer: Timer?
    private var isScroll: Bool = false
    
    /**
     *  根据传入的图片数组，初始化一个轮播图对象
     *
     *  - Parameters:
     *      - frame:             轮播图对象的frame
     *      - images:            图片数组，包含了要进行轮播图的图片
     *      - canCycle:          是否可以轮播，默认false
     *      - animationDuration: 自动滚动的时间间隔，如果给的值为0的时候不能自动进行轮播(双击可以暂停和继续)，默认0
     *
     *  - Returns: 初始化完成的轮播图对象
     */
    init!(frame: CGRect, urls: Array<String>, canCycle: Bool = false, animationDuration: TimeInterval = 0) {
        guard urls.count > 0 else {
            return nil
        }
        
        self.images = urls
        self.canCycle = canCycle
        self.animationDuration = animationDuration
        
        super.init(frame: frame)
        
        createScrollView()
        
        if canCycle && animationDuration > 0 {
            play(sender: nil)
        }
    }
    
    init!(frame: CGRect, images: Array<UIImage>, canCycle: Bool = false, animationDuration: TimeInterval = 0) {
        guard images.count > 0 else {
            return nil
        }
        
        self.images = images
        self.canCycle = canCycle
        self.animationDuration = animationDuration
        
        super.init(frame: frame)
        
        createScrollView()
        
        if canCycle && animationDuration > 0 {
            play(sender: nil)
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        images = []
        canCycle = false
        animationDuration = 0
        
        super.init(coder: aDecoder)
    }
    
    func changeImages(_ images: Array<UIImage>) {
        guard images.count > 0 else {
            return
        }
        
        self.images = images
        
        if scrollView != nil {
            scrollView.removeFromSuperview()
        }
        if pageControl != nil {
            pageControl.removeFromSuperview()
        }
        
        createScrollView()
    }
    
    func changeUrls(_ urls: Array<String>) {
        guard urls.count > 0 else {
            return
        }
        
        self.images = urls
        
        if scrollView != nil {
            scrollView.removeFromSuperview()
        }
        if pageControl != nil {
            pageControl.removeFromSuperview()
        }
        
        createScrollView()
    }
    
    private func createScrollView() -> Void {
        scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
        scrollView.contentSize = CGSize(width: frame.size.width * CGFloat(canCycle ? images.count + 2 : images.count), height: 0)
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.contentOffset = CGPoint(x: canCycle ? frame.size.width : 0, y: 0)
        scrollView.isPagingEnabled = true
        scrollView.delegate = self
        addSubview(scrollView)
        
        createImageViews()
        createPageControl()
        
        let autoPlay: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(play(sender:)))
        autoPlay.numberOfTapsRequired = 2
        if canCycle {
            addGestureRecognizer(autoPlay)
        }
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapAction(sender:)))
        tap.numberOfTapsRequired = 1
        addGestureRecognizer(tap)
        
        tap.require(toFail: autoPlay)
    }
    
    private func createPageControl() -> Void {
        pageControl = UIPageControl(frame: CGRect(x: 0, y: frame.size.height - 30, width: frame.size.width, height: 30))
        pageControl.numberOfPages = images.count
        pageControl.currentPage = currentIndex
        pageControl.pageIndicatorTintColor = UIColor.gray
        pageControl.currentPageIndicatorTintColor = UIColor.white
        pageControl.addTarget(self, action: #selector(pageChange(sender:)), for: .valueChanged)
        addSubview(pageControl)
    }
    
    private func createImageViews() -> Void {
        var temp: Array<Any> = images
        if canCycle {
            temp.insert(images.last!, at: 0)
            temp.append(images.first!)
        }
        
        for i in 0 ..< temp.count {
            let imageView: UIImageView = UIImageView(frame: CGRect(x: frame.size.width * CGFloat(i), y: 0, width: frame.size.width, height: frame.size.height))
            imageView.backgroundColor = UIColor.black
            if temp[i] is String {
                imageView.kf.setImage(with: URL(string: temp[i] as! String), placeholder: #imageLiteral(resourceName: "placeImage6-5"))
            } else {
                imageView.image = temp[i] as? UIImage
            }
            imageView.isUserInteractionEnabled = true
            scrollView.addSubview(imageView)
        }
    }
    
    @objc private func play(sender: UITapGestureRecognizer?) -> Void {
        if !isRunning {
            if animationDuration != 0 {
                timer = Timer.scheduledTimer(timeInterval: animationDuration, target: self, selector: #selector(start(sender:)), userInfo: nil, repeats: true)
            }
            
//            timer?.fire()
            isRunning = true
        } else {
            timer?.invalidate()
            timer = nil
            isRunning = false
        }
    }
    
    @objc private func tapAction(sender: UITapGestureRecognizer) -> Void {
        if yyDelegate != nil && yyDelegate!.responds(to: #selector(YYCycleViewDelegate.cycleView(_:didSelectImageAt:))) {
            yyDelegate!.cycleView!(self, didSelectImageAt: currentIndex)
        }
    }
    
    @objc private func start(sender: Timer) -> Void {
        scrollView.setContentOffset(CGPoint(x: CGFloat(currentIndex + 2) * frame.size.width, y: scrollView.contentOffset.y), animated: true)
        
        if Int(scrollView.contentOffset.x / frame.size.width) == images.count {
            scrollView.contentOffset = CGPoint(x: 0, y: 0)
        }
    }
    
    @objc private func pageChange(sender: UIPageControl) -> Void {
        if canCycle {
            scrollView.setContentOffset(CGPoint(x: frame.size.width * CGFloat(sender.currentPage + 1), y: 0), animated: true)
        } else {
            scrollView.setContentOffset(CGPoint(x: frame.size.width * CGFloat(currentIndex), y: 0), animated: true)
        }
    }
    
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        timer?.fireDate = Date.distantFuture
        if !isScroll && yyDelegate != nil && yyDelegate!.responds(to: #selector(YYCycleViewDelegate.cycleView(_:willBeginDraggingAt:))) {
            yyDelegate?.cycleView!(self, willBeginDraggingAt: currentIndex)
        }
        isScroll = true
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        timer?.fireDate = Date(timeIntervalSinceNow: animationDuration)
        if yyDelegate != nil && yyDelegate!.responds(to: #selector(YYCycleViewDelegate.cycleView(_:didEndDeceleratingAt:))) {
            yyDelegate?.cycleView!(self, didEndDeceleratingAt: currentIndex)
        }
        isScroll = false
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if canCycle {
            let currentPoint: CGPoint = scrollView.contentOffset
            if currentPoint.x < frame.size.width / 2 {
                scrollView.contentOffset.x = CGFloat(images.count) * frame.size.width + currentPoint.x
            } else if currentPoint.x > (CGFloat(images.count) + 0.5) * frame.size.width {
                scrollView.contentOffset.x = currentPoint.x - CGFloat(images.count) * frame.size.width
            }
        }
        pageControl.currentPage = currentIndex
    }
    
}
